﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading;
using CI;
using CI.Interfaces;
using CI.Organism;

namespace Mesopotamia.UnitTests
{
    public class MockedOrganism : IOrganism
    {
        public MockedOrganism(OrganismCollection organisms, bool born, INeuralSystem neuralSystem)
        {
            Organisms = organisms;
            Born = born;
            NeuralSystem = neuralSystem;
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        /// <filterpriority>2</filterpriority>
        public void Dispose()
        {
            throw new NotImplementedException();
        }

        /// <summary>DNA for the Organism</summary>
        public IDNA DNA
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        /// <summary>Organism's GUID used to uniquely identify it in the Organism</summary>
        public Guid Guid
        {
            get { throw new NotImplementedException(); }
        }

        /// <summary>This organisms parents</summary>
        public SynchronizedCollection<IOrganism> ParentOrganisms
        {
            get { throw new NotImplementedException(); }
        }

        public event SynapseIODelegate EnergyChangeEvent;
        public event SynapseIODelegate EnergySetEvent;
        public event Action HeartbeatChangeEvent;
        public event Action RegistrationChangeEvent;
        public event Action BornChangeEvent;
        public event Action<ILocation> LocationChangeEvent;

        /// <summary>Neural network for the Organism</summary>
        public INeuralSystem NeuralSystem { get; set; }

        /// <summary>Organisms Heartbeat, this triggers the processing of the DNA</summary>
        public void Heartbeat()
        {
            throw new NotImplementedException();
        }

        public void LocationChange(ILocation location)
        {
            throw new NotImplementedException();
        }

        public void RegistrationChange()
        {
            throw new NotImplementedException();
        }

        public void BornChange()
        {
            throw new NotImplementedException();
        }

        /// <summary>Terminate Organism, this will usually be because of bad dna, so move it to the dead collection</summary>
        public void Terminate(string reason)
        {
            throw new NotImplementedException();
        }

        /// <summary>Terminate Organism and move it to the inactive collection, not the dead collection like a normal terminate will do</summary>
        public void TerminateAndDestroy(string reason)
        {
// lock the collections to change it
            // if its in the alive List then the kill it
            if (Monitor.TryEnter(Organisms.Alive, Globals.CriticalAcquireLockTimeout))
            {
                try
                {
                    if (Organisms.Alive.Contains(this))
                    {

                        if (Monitor.TryEnter(Organisms.Inactive, Globals.CriticalAcquireLockTimeout))
                        {
                            try
                            {
                                // if its still in the alive list
                                if (Organisms.Alive.Contains(this))
                                {
                                    // remove it from alive
                                    Organisms.AliveRemove(this);

                                    // add it to dead
                                    Organisms.InactiveAdd(this);
                                }
                            }
                            finally
                            {
                                Monitor.Exit(Organisms.Inactive);
                            }
                        }
                        else
                        {
                            throw new OrganismException("unable to acquire lock on Organisms.Inactive");
                        }
                    }
                }
                finally
                {
                    Monitor.Exit(Organisms.Alive);
                }
            }
            else
            {
                throw new OrganismException("Unable to acquire lock on Organisms.Alive");
            }

            // lock the collections to change it
            // if its in the dead List then the kill it
            if (Monitor.TryEnter(Organisms.Dead, Globals.CriticalAcquireLockTimeout))
            {
                try
                {
                    if (Organisms.Dead.Contains(this))
                    {
                        if (Monitor.TryEnter(Organisms.Inactive, Globals.CriticalAcquireLockTimeout))
                        {
                            try
                            {
                                // if its still in the alive list
                                if (Organisms.Dead.Contains(this))
                                {
                                    // remove it from alive
                                    Organisms.DeadRemove(this);

                                    // add it to dead
                                    Organisms.InactiveAdd(this);
                                }
                            }
                            finally
                            {
                                Monitor.Exit(Organisms.Inactive);
                            }
                        }
                        else
                        {
                            throw new OrganismException("Unable to acquire lock on Organisms.Inactive");
                        }
                    }
                }
                finally
                {
                    Monitor.Exit(Organisms.Dead);
                }
            }
            else
            {
                throw new OrganismException("Unable to acquire lock on Organisms.Dead");
            }
            
        }

        /// <summary>Active state of the Organism. If their eaten etc don't process them</summary>
        public ActiveState ActiveState
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        /// <summary>Organism energy level, when this gets to 0 the Organism is Dead</summary>
        public long Energy
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        /// <summary>Organism Init energy level the Organism had at creation</summary>
        public long InitEnergy
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        /// <summary>Body mass energy, this is the energy left in the Organism once it is dead</summary>
        public long BMEnergy
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        /// <summary>Collision Impact Energy Transfer, this is how much is taken off a coliding Organism if it is the largest of the two Organism</summary>
        public long CIET
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        /// <summary>Initial Collision Impact Energy Transfer, this is how much is taken off a coliding Organism if it is the largest of the two Organism</summary>
        public long InitCIET
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        /// <summary>Calculated fitness value assigned by the fitness function</summary>
        public long FitnessValue
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        /// <summary>HeartBeat count for the Organism</summary>
        public uint HeartbeatCount
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        /// <summary>Hosting Environment of the Organism, used to ask for location etc.</summary>
        public IHostingEnvironment HostingEnvironment
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        /// <summary>Organisms Location, used in collison detection</summary>
        public ILocation Location
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        /// <summary>
        /// This indicates if the location has changed and also to reset the flag
        /// From this we can decide to redraw maps and calculate collisions
        /// </summary>
        public bool LocationDirty
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        /// <summary>All the organisms in the environment, the collection it belongs to..</summary>
        public IOrganismCollection Organisms { get; set; }

        /// <summary>All the cells in the Organism</summary>
        public ICellCollection Cells
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        /// <summary>
        /// Has the organism been born yet, they could be in seed type situation and not had the zygote active yet
        /// Usually determined by checking the zygote..
        /// If not born then we dont have to do neural or fitness function
        /// </summary>
        public bool Born { get; private set; }

        /// <summary>
        /// do a equals comparison of one organism type to another only comparing the value types, no refference comparisons
        /// </summary>
        /// <param name="organism">organism to compare against</param>
        /// <returns>true if equal value types</returns>
        public bool EqualsValueTypes(IOrganism organism)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Get the organisms zygote
        /// </summary>
        /// <returns></returns>
        public ICell Zygote()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Get the SyanpseIO manifest for the organism
        /// </summary>
        /// <returns></returns>
        public ReadOnlyCollection<SynapseIO> GetIOManifest()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Get the synapseIO with the corresponding binding name
        /// </summary>
        /// <param name="bindingName"></param>
        /// <returns></returns>
        public SynapseIO GetSynapseIO(string bindingName)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Get the synapseIO with the corresponding Guid
        /// </summary>
        /// <param name="guid"></param>
        /// <returns></returns>
        public SynapseIO GetSynapseIO(Guid guid)
        {
            throw new NotImplementedException();
        }
    }
}